/**
 * 轻量级JS模块化加载管理
 * Author: 陆楚良
 * Version: 1.0.0
 * Date: 2014/11/21
 * QQ: 519998338
 *
 * https://git.oschina.net/luchg/Glight.js.git
 *
 * License: http://www.apache.org/licenses/LICENSE-2.0
 */
!function(window,document, undefined){

function isType(type) {
  return function(obj) {
    return {}.toString.call(obj) == "[object " + type + "]"
  }
}
var isString = isType("String");
var isFunction = isType("Function");


var RE_REQUIRE = /"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^\/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g;
var RE_BASE = new RegExp(RE_REQUIRE.source.replace(/require/g,"base"));
var RE_SLASH = /\\\\/g;
var RE_EXT = /[\?#].*/;
var RE_SEP = /\\/g;





/*head节点*/
var head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
/*base节点*/
var baseElement = head.getElementsByTagName("base")[0];
/*老版本webkit*/
var isOldWebKit = +navigator.userAgent.replace(/.*(?:AppleWebKit|AndroidWebKit)\/(\d+).*/, "$1") < 536;
var loadQ = {};

var currentlyAddingScript;
var interactiveScript;
//加载资源
function loadResource(url, onload){
	var ext  = url.split(/\./).pop();
	var isCSS = (ext.replace(RE_EXT, '').toLowerCase()=="css");
	var node = document.createElement(isCSS?"link":"script");
	var absPath;
	if(isCSS){
		node.rel = "stylesheet";
		node.href= url;
		absPath = node.href;
	}else{
	    node.async = true;
	    node.src = url;
	    absPath = node.src;
	}
	if(absPath in loadQ){
		loadQ[absPath].queue(function(){
			setTimeout(onload, 1);
			loadQ[absPath].dequeue();
		});
		return;
	}
	var supportOnload = "onload" in node;
	loadQ[absPath] = Queue();
	loadQ[absPath].queue(function(){
		var done = function(){
				node.onload = node.onreadystatechange = null;
				!isCSS && head.removeChild(node);
				setTimeout(onload, 1, absPath, isCSS, node);
				node=null;
				loadQ[absPath].dequeue();
			};
		if(isCSS && (isOldWebKit || !supportOnload)){
			setTimeout(function(){pollCss(node,done)},1);
		}
		else if(supportOnload){
			node.onload = done;
			node.onerror=function(){done()};
		}
		else{
			node.onreadystatechange = function() {
				if (/loaded|complete/.test(node.readyState)) {
					done();
				}
			}
		}
		currentlyAddingScript = node;
		baseElement ? head.insertBefore(node, baseElement) : head.appendChild(node);
		currentlyAddingScript = null;
	});
}

// 轮询监视css加载
function pollCss(node,callback){
	var sheet = node.sheet,
		isLoaded;
	if (isOldWebKit) {
		if (sheet) {
			isLoaded = true;
		}
	}
	else if (sheet) {
		try {
			if (sheet.cssRules) {
				isLoaded = true;
			}
		} catch (e) {
			if (e.name === "NS_ERROR_DOM_SECURITY_ERR") {
				isLoaded = true;
			}
		}
	}
	isLoaded ? callback() : setTimeout(function() {pollCss(node, callback)}, 100);
}

var AbsPathElement = document.createElement("script");
function getAbsPath(node){
	if(isString(node)){
		AbsPathElement.src = node;
		node = AbsPathElement;
	}
	return node.hasAttribute ? // non-IE6/7
			node.src :
			// see http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
			node.getAttribute("src", 4);
}

function getCurrAbsPath() {
	if (currentlyAddingScript) {
		return getAbsPath(currentlyAddingScript);
	}
	if (interactiveScript && interactiveScript.readyState === "interactive") {
		return getAbsPath(interactiveScript);
	}
	// FF,Chrome
	if (document.currentScript){
		return document.currentScript.src;
	}
	var stack;
	try {
		a.b.c(); //强制报错,以便捕获e.stack
	} catch(e) {//safari的错误对象只有line,sourceId,sourceURL
		stack = e.stack;
		if(!stack && window.opera){
			//opera 9没有e.stack,但有e.Backtrace,但不能直接取得,需要对e对象转字符串进行抽取
			stack = (String(e).match(/of linked script \S+/g) || []).join(" ");
		}
	}
	if(stack) {
		/**e.stack最后一行在所有支持的浏览器大致如下:
		*chrome23:
		* at http://127.0.0.1/data.js:4:1
		*firefox17:
		*@http://127.0.0.1/data.js:4
		*opera12:
		*@http://127.0.0.1/data.js:4
		*IE10:
		*  at Global code (http://113.93.50.63/data.js:4:1)
		*/
		stack = stack.split( /[@ ]/g).pop();//取得最后一行,最后一个空格或@之后的部分
		stack = stack[0] == "(" ? stack.slice(1,-1) : stack;
		return stack.replace(/(:\d+)?:\d+$/i, "");//去掉行号与或许存在的出错字符起始位置
	}
	// IE 5-9
	var scripts = head.getElementsByTagName("script")
	for (var i = scripts.length - 1; i >= 0; i--) {
		var script = scripts[i]
		if (script.readyState === "interactive") {
			interactiveScript = script;
			return getAbsPath(interactiveScript);
		}
	}
}


// 简单的队列引擎
function Queue(){
	var Q={
		l:[],c:1,
		queue:function(callback){
			Q.l.push(callback);
			Q.c && Q.dequeue();
			return Q;
		},
		dequeue:function(){
			Q.c = 0;
			var s = Q.l.shift();
	        if(s){
	        	isFunction(s) && s.call(Q);
	        }else{
	            Q.c = 1;
	        }
	        return Q;
		}
	};
	return Q;
}


function base(s){
	if(!s){
		return GlightJS.base ? base(GlightJS.base) : "";
	}
	s = s.replace(RE_SEP, "/");
	if(s.substr(s.length-1)!="/")
		s += "/";
	return s;
}
function URI(s,d){
	var ext = s.toLowerCase().split(/\./).pop();
	p = ext.replace(RE_EXT, '');
	s = s.replace(RE_SEP, "/");
	s = (p==ext && p!="css" && p!="js") ? s+".js" : s;
	return /^(https?:\/\/|\.?\.?\/)/.test(s) ? s : d+s;
}
function dep(factory, re){
	var ret=[];
	factory.toString().replace(RE_SLASH, "").replace(re, function(a, a1, a2) {a2 && ret.push(a2)});
	return ret;
}




var module={};
function require(s){
	return (s in module) ? module[s].Export : undefined;
};


// 事件
var EVENT_LOAD = {},EVENTS={};
function Event(name, callback){
	if(callback){
		if(name in EVENT_LOAD){
			callback();
		}else{
			if(name in EVENTS)
				EVENTS[name].push(callback);
			else
				EVENTS[name] = [callback];
		}
	}
	else{
		EVENT_LOAD[name] = true;
		if(name in EVENTS){
			for(var i=0;i<EVENTS[name].length;i++){
				!function(f){
					setTimeout(f, 1);
				}(EVENTS[name][i]);
			}
		}
	}
}

function define(factory){
	if(isFunction(factory)){
		var i,
			deps=dep(factory, RE_REQUIRE),
			baseURI=base(dep(factory, RE_BASE)[0]),
			length=deps.length,
			length2=length,
			Q = Queue(),
			_require = function(name){
				if(!name || !isString(name))
					return undefined;
				return require(getAbsPath(URI(name,baseURI)));
			},
			_base = function(url){
				if(!url || !isString(url))
					return baseURI;
				return base(url);
			};
		_require.async = function(name, callback){
				if(!name || !isString(name))
					return undefined;
				var absPath = getAbsPath(URI(name,baseURI));
				Event(absPath, function(){
					isFunction(callback) && callback(require(absPath));
				});
				loadModule([name], baseURI);
			};
		var src = getCurrAbsPath();
		var emit= {
			deps : deps,
			factory : factory,
			require : _require
		};
		for(i=0; i<length; i++){
			Event(getAbsPath( URI(deps[i], baseURI)), function(){
				if((length2-=1)==0){
					emit.Export = factory(_require, _base);
					Event(src);
				}
			});
		}
		if(src)module[src]=emit;
		if(length==0){
			emit.Export = factory(_require, _base);
			Event(src);
		}else{
			loadModule([].concat(deps), baseURI);
		}
	}
}

function loadModule(deps, baseURI){
	if(deps.length==0){
		return;
	}
	var url = URI(deps.shift(), baseURI);
	loadResource(url, function(absPath, isCSS, node){
		if(isCSS){
			module[absPath] = {
				deps : [],
				Export  : node
			};
			Event(absPath);
		}
		loadModule(deps, baseURI);
	});
}




var oDefine = window.define;
var GlightJS  = window.GlightJS = {
	base:"",
	define:define,
	noConflict : function(name){
		window.define = oDefine;
		if(name){
			window[name] = define;
		}
		return define;
	}
};
window.define = define;
}(window,document);